const treeify = require('treeify');
const {
  pair,
  head,
  tail,
  list,
  isNull,
  map,
  append,
  reverse,
} = require('./05');

function print(pair) {
  console.log(treeify.asTree(pair, true));
}
function isPair(x) {
  return (
    Object.prototype.toString.call(x) === '[object Object]' &&
    'head' in x &&
    'tail' in x
  );
}

function countLeaves(x) {
  if (isNull(x)) return 0;
  if (!isPair(x)) return 1;

  return countLeaves(head(x)) + countLeaves(tail(x));
}

const tree = list(1, list(2, list(3, 4)));

function reverse2(items) {
  return reverseIter(items);

  function reverseIter(items, result = null) {
    if (isNull(items)) return result;
    return reverseIter(tail(items), pair(result, reverse(head(items))));
  }
}
// 作业：reverseTree
const reverseExample = list(list(1, 2), list(3, 4));
function reverseTree(tree) {
  if (isNull(tree)) return null;
  if (!isPair(tree)) return tree;
  return append(reverseTree(tail(tree)), pair(reverseTree(head(tree)), null));
}
//转迭代（0528）
function reverseTree2(tree) {
  return reverseIter(tree);

  function reverseIter(tree, result = null) {
    if (isNull(tree)) return result;
    if (!isPair(tree)) return tree;
    return reverseIter(tail(tree), pair(reverseIter(head(tree)), result));
  }
}

function doubleTree(tree) {
  if (isNull(tree)) return tree;
  if (!isPair(tree)) return tree * 2;

  return pair(doubleTree(head(tree)), doubleTree(tail(tree)));
}

function tripleTree(tree) {
  return map(tree, subTree =>
    isPair(subTree) ? tripleTree(subTree) : subTree * 3
  );
}

// 练习：不使用map & 使用map
function squareTree(tree) {
  if (isNull(tree)) return tree;
  if (!isPair(tree)) return tree ** 2;

  return pair(squareTree(head(tree)), squareTree(tail(tree)));
}

function squareTree2(tree) {
  return map(tree, subTree =>
    isPair(subTree) ? squareTree2(subTree) : subTree ** 2
  );
}

function treeMap(tree, fn) {
  if (isNull(tree)) return tree;
  return pair(head(tree), treeMap(tail(tree), fn));
}
function squareTreeWithTreeMap(tree) {
  return treeMap(tree, x => x ** 2);
}
//0528
// (1, 2, 3) =>
// ((), (1), (2), (3), (1, 2), (1, 3), (2, 3), (1, 2, 3))
function subsets(s) {
  if (isNull(s)) return list(null);
  const rest = subsets(tail(s));
  const fn = x => pair(head(s), x);
  return append(rest, map(rest, fn));
}
// print(subsets(list(1, 2, 3)));

function sum(tree) {
  if (isNull(tree)) return 0;
  if (!isPair(tree)) return oddSquare(tree);

  return sum(head(tree)) + sum(tail(tree));
}
function oddSquare(n) {
  if (n % 2 == 0) return 0;
  return n ** 2;
}

module.exports = {
  isPair,
  print,
};
